
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.ArrayList;

/**
 * Clase que que crea las fichas para el juego.
 *
 * @author Matías Díaz
 * @author Sergio Flores
 */
public class Ficha
{

    private int tamano;
    private ArrayList<JTriangulo> fichas;
    private ArrayList<JTriangulo> fichasSolucionadas;
    private ArrayList<Color> colores;
    private JTriangulo fichaAux;

    /**
     * Contructor de la clase, la cual inicializa todas las variable.
     */
    public Ficha ()
    {
        this.tamano = 3;
        this.fichas = new ArrayList<> ();
        this.fichasSolucionadas = new ArrayList<> ();
        this.fichaAux = new JTriangulo ();

        this.setColores ();
    }

    /**
     * Contructor de la clase, la cual inicializa todas las variables.
     *
     * @param tamano esta variable entrega un string con el tamaño
     * correspondiente
     * al tablero a utilizarse.
     */
    public Ficha ( String tamano )
    {
        this.tamano = determinarTamaño ( tamano );
        this.fichas = new ArrayList<> ();
        this.fichasSolucionadas = new ArrayList<> ();

        this.fichaAux = new JTriangulo ();
        this.setColores ();
        creaLaFicha ();
    }

    /**
     * Metodo que retorna las fichas
     *
     * @return retorna el arraylist de fichas creadas.
     */
    public ArrayList<JTriangulo> getFichas ()
    {
        return this.fichas;
    }

    /**
     * metodo que retorna el tamaño del tablero
     *
     * @return retorna el tamaño como entero.
     */
    public int getMatriz ()
    {
        return tamano;
    }

    /**
     * metodo que cambia el tamaño del tablero
     *
     * @param matriz corresponde al valor nuevo para el tamaño
     */
    public void setMatriz ( String matriz )
    {
        this.tamano = determinarTamaño ( matriz );
    }

    /**
     * Este metodo determina el tamaño en entero dado un string.
     *
     * @param tamano corresponde al tamaño a evaluar
     * @return retorna el tamaño pero como un entero
     */
    private int determinarTamaño ( String tamano )
    {
        int numero = ( -1 );
        switch ( tamano )
        {
            case CommandName.DOS_DOS:
                numero = 2;
                break;
            case CommandName.TRES_TRES:
                numero = 3;
                break;
            case CommandName.CUATRO_CUATRO:
                numero = 4;
                break;
            case CommandName.CINCO_CINCO:
                numero = 5;
                break;
            case CommandName.SEIS_SEIS:
                numero = 6;
                break;
            default:
                numero = 3;
                break;
        }
        return numero;
    }

    /**
     * Metodo que crea la ficha.
     */
    private void creaLaFicha ()
    {
        Point punto = new Point ( 700 , 25 ); // punto inicial
        for ( int i = 0 ; i < this.tamano ; i++ )
        {
            for ( int j = 0 ; j < this.tamano ; j++ )
            {
                ArrayList<Integer> numeros = crearNumerosFicha ();

                int nUp = numeros.get ( 0 );
                int nLeft = numeros.get ( 1 );
                int nDown = numeros.get ( 2 );
                int nRight = numeros.get ( 3 );
                fichasSolucionadas.add ( new JTriangulo ( nUp , nDown , nLeft , nRight , colores.get ( nUp ) , colores.get ( nDown ) , colores.get ( nLeft ) , colores.get ( nRight ) , punto ) );
                punto = new Point ( punto.x + 102 , punto.y );
            }
            punto = new Point ( 700 , punto.y + 102 );
        }
        revolver ();
    }

    /**
     * Metodo que pinta todos las fichas en el tablero
     *
     * @param g es donde se debe pintar.
     */
    public void paint ( Graphics g )
    {
        for ( JTriangulo trian : this.fichas )
        {
            trian.paint ( g );
        }
    }

    /**
     * Metodo que crea un arrayList de colores,
     * de los cuales al crear la ficha se accederán
     * a ellos.
     */
    private void setColores ()
    {
        this.colores = new ArrayList<> ();
        this.colores.add ( Color.black.brighter () );
        this.colores.add ( Color.orange.darker () );
        this.colores.add ( Color.red );
        this.colores.add ( new Color ( 236 , 79 , 0 ) );//Dark Orange
        this.colores.add ( new Color ( 255 , 215 , 0 ) );//yellow
        this.colores.add ( new Color ( 0 , 205 , 0 ) );//green
        this.colores.add ( new Color ( 0 , 47 , 204 ) );//blue
        this.colores.add ( new Color ( 139 , 0 , 139 ) );//magenta
        this.colores.add ( new Color ( 160 , 160 , 160 ) );//gray
        this.colores.add ( new Color ( 14 , 203 , 255 ) );//Cyan
    }

    /**
     * Este metodo mueve una ficha a un nuevo punto
     *
     * @param point corresponde al punto donde se va a mover la ficha
     */
    public void moveFicha ( Point point )
    {
        fichaAux.moveTriangulo ( point );
    }

    /**
     * Metodo que selecciona la ficha que se moverá
     *
     * @param point dado este punto se determina se hay una pieza para mover o
     * no
     * @return se retorna un boolean, si es que se puede mover una ficha o no
     */
    public boolean estaFichaMovere ( Point point )
    {
        for ( int i = this.fichas.size () - 1 ; i >= 0 ; i-- )
        {
            JTriangulo trian = this.fichas.get ( i );
            Point punto = trian.getPuntoInicial ();
            if ( point.x >= punto.x && point.y >= punto.y && point.x < ( punto.x + 100 ) && point.y < ( punto.y + 100 ) )
            {
                this.fichaAux = trian;
                this.fichas.remove ( trian );
                this.fichas.add ( fichaAux );
                return true;
            }

        }
        return false;
    }

    /**
     * Metodo que retorna la ficha que se ha seleccionado
     * como para moverla
     *
     * @return se retorna la ficha
     */
    public JTriangulo getFichaAux ()
    {

        return this.fichaAux;
    }

    /**
     * Metodo que permite crear los numeros para las fichas
     *
     * @return un arrayList de numeros correspondiente a la
     * la ficha en particular.
     */
    public ArrayList<Integer> crearNumerosFicha ()
    {
        ArrayList<Integer> numeros = new ArrayList<> ();

        if ( this.fichasSolucionadas.isEmpty () )
        {
            int nDown = ( int ) ( Math.random () * 10 );
            int nUp = ( int ) ( Math.random () * 10 );
            int nRight = ( int ) ( Math.random () * 10 );
            int nLeft = ( int ) ( Math.random () * 10 );
            numeros.add ( nUp );
            numeros.add ( nLeft );
            numeros.add ( nDown );
            numeros.add ( nRight );
            return numeros;
        }
        else
        {

            if ( ( ( this.fichasSolucionadas.size () ) - this.tamano ) >= 0 )
            {
                int nUp = this.fichasSolucionadas.get ( ( this.fichasSolucionadas.size () ) - this.tamano ).getNumeroDown ();
                numeros.add ( nUp );
            }
            else
            {
                int nUp = ( int ) ( Math.random () * 10 );
                numeros.add ( nUp );
            }

            if ( ( this.fichasSolucionadas.size () ) % ( this.tamano ) == 0 )
            {
                int nLeft = ( int ) ( Math.random () * 10 );
                numeros.add ( nLeft );
            }
            else
            {
                int nLeft = this.fichasSolucionadas.get ( ( this.fichasSolucionadas.size () - 1 ) ).getNumeroRight ();
                numeros.add ( nLeft );
            }
            int nDown = ( int ) ( Math.random () * 10 );
            int nRight = ( int ) ( Math.random () * 10 );

            numeros.add ( nDown );
            numeros.add ( nRight );
        }
        return numeros;
    }

    /**
     * metodo que revolve la solucion de las fichas.
     */
    public void revolver ()
    {
        ArrayList<JTriangulo> fichasTemp = ( ArrayList<JTriangulo> ) fichasSolucionadas.clone ();
        ArrayList<Integer> num = new ArrayList<> ();
        int count = fichasTemp.size ();
        //lo llenamos de numeros
        for ( int i = 0 ; count > i ; i++ )
        {
            num.add ( i );
        }

        while ( !num.isEmpty () )
        {
            int numero = ( int ) ( Math.random () * num.size () );
            try
            {
                JTriangulo temp = fichasTemp.get ( num.get ( numero ) );
                this.fichas.add ( temp );
                num.remove ( numero );
            }
            catch ( Exception e )
            {
            }
        }

        //cambio su punto inicial de cada pieza, por que o si no.. me lo mostraría de forma ordenada igual
        this.setPuntoInicial ( new Point ( 700 , 25 ) , this.fichas ); // punto inicial

    }

    /**
     * cambia el punto inicial de cada una de las fichas dado el punto inicial
     * de el tablero.
     *
     * @param punto corresponde al punto inicial del tablero, por el cual, todas
     * las fichas
     * se deben configurar.
     * @param fichas corresponde a las fichas a las que queremos cambiarle el
     * punto
     */
    public void setPuntoInicial ( Point punto , ArrayList<JTriangulo> fichas )
    {
        int rememberPuntoX = punto.x;
        int count = 0;
        for ( int i = 0 ; i < this.tamano ; i++ )
        {
            for ( int j = 0 ; j < this.tamano ; j++ )
            {
                fichas.get ( count ).setPuntoInicial ( punto );
                punto = new Point ( punto.x + 102 , punto.y );
                count++;
            }
            punto = new Point ( rememberPuntoX , punto.y + 102 );
        }
    }

    /**
     * Metodo que muestra la solucion del juego.
     */
    public void mostrarSolucion ()
    {
        this.fichas = ( ArrayList<JTriangulo> ) this.fichasSolucionadas.clone ();
        setPuntoInicial ( new Point ( 25 , 25 ) , this.fichas );
    }
}